package com.xiaotao.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xiaotao.entity.Room;
import com.xiaotao.util.RedisCacheUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@ServerEndpoint("/chatWebSocket/{roomId}/{userId}")
@Slf4j
@Component
public class WebSocketService {
    private static RedisCacheUtil redisCacheUtil;
    @Autowired
    public void setRedisCacheUtil(RedisCacheUtil redisCacheUtil) {
        WebSocketService.redisCacheUtil = redisCacheUtil;
    }
    private static int onlineCount = 0;
    private static ConcurrentHashMap<String, Room> roomMap = new ConcurrentHashMap<>();
    private Session session;
    private String userId = "";
    private String roomId = "";

    @OnOpen
    public void onOpen(Session session,@PathParam("roomId") String roomId,@PathParam("userId") String userId){
        this.session = session;
        this.userId = userId;
        this.roomId = roomId;
        Room room = roomMap.computeIfAbsent(roomId, k -> new Room(roomId, userId, 10));
        if (room.getUserMap().size() >= room.getMaxUsers()) {
            try {
                sendMessage("{\"type\":\"error\",\"message\":\"房间人数已满（上限" + room.getMaxUsers() + "人），请稍后再进！\"}");
                session.close();
                return;
            } catch (IOException e) {
                log.error("人数超限关闭连接失败", e);
                return;
            }
        }
        room.getUserMap().put(userId, this);
        addOnlineCount();
        log.info("用户{}进入聊天室{}（房主：{}），当前人数：{}，上限：{}",
                userId, roomId, room.getOwnerId(), room.getUserMap().size(), room.getMaxUsers());
        try{
            loadHistoryMessages();
            JSONObject systemMsg = new JSONObject();
            systemMsg.put("type", "system");
            systemMsg.put("userId", "system");
            systemMsg.put("message", "进入聊天室成功");
            systemMsg.put("isOwner", userId.equals(room.getOwnerId()));
            systemMsg.put("roomId", this.roomId);
            systemMsg.put("roomOwner", room.getOwnerId());
            sendMessage(systemMsg.toJSONString());
            broadUserList(room);
        }catch (IOException e){
            log.error("用户："+userId+",连接失败！！");
        }
    }
    @OnClose
    public void onClose(){
        Room room = roomMap.get(roomId);
        if (room != null) {
            room.getUserMap().remove(userId);
            log.info("用户{}退出聊天室{}，当前人数：{}", userId, roomId, room.getUserMap().size());
            try {
                broadUserList(room);
            } catch (IOException e) {
                log.error("广播用户列表失败", e);
            }
            if (room.getUserMap().isEmpty()) {
                roomMap.remove(roomId);
                log.info("聊天室{}已解散（无用户）", roomId);
            }
        }
        subOnlineCount();
    }



    @OnMessage
    public void onMessage(String message){
        Room room = roomMap.get(roomId);
        if (room == null)
            return;
        log.info("聊天室{}的用户{}发送消息：{}", roomId, userId, message);
        if(message!= null){
            log.info(message);
            try {
                JSONObject jsonObject = JSON.parseObject(message);
                String msgType = jsonObject.getString("type");
                if ("kick".equals(msgType)) {
                    if (!userId.equals(room.getOwnerId())) {
                        sendMessage("{\"type\":\"error\",\"message\":\"无权限！只有房主可踢人\"}");
                        return;
                    }
                    if (room.getMaxUsers() == 2) {
                        sendMessage("{\"type\":\"error\",\"message\":\"私聊房间不支持踢人操作\"}");
                        return;
                    }
                    String targetUserId = jsonObject.getString("targetUserId");
                    WebSocketService targetUser = room.getUserMap().get(targetUserId);
                    if (targetUser != null) {
                        targetUser.session.close();
                        room.getUserMap().remove(targetUserId);
                        broad(room, "{\"type\":\"system\",\"message\":\"用户" + targetUserId + "被房主踢出房间\"}");
                        broadUserList(room);
                    }
                    return;
                }
                if ("changeOwner".equals(msgType)) {
                    String targetUserId = jsonObject.getString("targetUserId");
                    changeOwner(targetUserId);
                    return;
                }
                if ("setMaxUsers".equals(msgType)) {
                    if (!userId.equals(room.getOwnerId())) {
                        sendMessage("{\"type\":\"error\",\"message\":\"无权限！只有房主可修改人数上限\"}");
                        return;
                    }
                    int newMax = jsonObject.getIntValue("maxUsers");
                    room.setMaxUsers(newMax);
                    broad(room, "{\"type\":\"system\",\"message\":\"房间人数上限已修改为" + newMax + "人\"}");
                    return;
                }
                jsonObject.put("roomId", this.roomId);
                jsonObject.put("userId", this.userId);
                jsonObject.put("type", "chat");
                jsonObject.put("sendTime",System.currentTimeMillis());
                String messageJson = jsonObject.toJSONString();
                String cacheKey = "room:messages:" + this.roomId;
                redisCacheUtil.getListOperations().rightPush(cacheKey, messageJson);
                redisCacheUtil.expire(cacheKey, 24, TimeUnit.HOURS);
                room.getUserMap().forEach((u, service) -> {
                    if(u.equals(this.userId)) return;
                    try{
                        service.sendMessage(jsonObject.toJSONString());
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                });
            } catch (Exception e) {
                log.error("消息处理失败", e);
            }
        }
    }

    private void broad(Room room, String message) throws IOException {
        for (WebSocketService user : room.getUserMap().values()) {
            user.sendMessage(message);
        }
    }
    private void broadUserList(Room room) throws IOException {
        JSONObject userListMsg = new JSONObject();
        userListMsg.put("type", "system");
        userListMsg.put("userList", new ArrayList<>(room.getUserMap().keySet()));
        broad(room, userListMsg.toJSONString());
    }

    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
    public void changeOwner(String targetUserId) throws IOException {
        Room room = roomMap.get(roomId);
        if (room == null) {
            sendMessage("{\"type\":\"error\",\"message\":\"房间不存在！\"}");
            return;
        }
        if (!userId.equals(room.getOwnerId())) {
            sendMessage("{\"type\":\"error\",\"message\":\"无权限！只有房主可移交权限\"}");
            return;
        }
        if (!room.getUserMap().containsKey(targetUserId)) {
            sendMessage("{\"type\":\"error\",\"message\":\"目标用户不在房间内！\"}");
            return;
        }
        if (userId.equals(targetUserId)) {
            sendMessage("{\"type\":\"error\",\"message\":\"无需移交！你已是房主\"}");
            return;
        }
        String oldOwnerId = room.getOwnerId();
        room.setOwnerId(targetUserId);
        String systemMsg = String.format(
                "{\"type\":\"system\",\"message\":\"房主已变更：%s → %s\"}",
                oldOwnerId, targetUserId
        );
        broad(room, systemMsg);
        broadUserList(room);
        WebSocketService newOwner = room.getUserMap().get(targetUserId);
        newOwner.sendMessage("{\"type\":\"system\",\"message\":\"你已成为房间房主\",\"isOwner\":true,\"roomOwner\":\"" + targetUserId + "\"}");
        sendMessage("{\"type\":\"system\",\"message\":\"房主权限已移交成功\",\"isOwner\":false,\"roomOwner\":\"" + targetUserId + "\"}");
    }
    private void loadHistoryMessages() throws IOException {
        String cacheKey = "room:messages:" + this.roomId;

        Long messageCount = redisCacheUtil.getListOperations().size(cacheKey);
        if (messageCount != null && messageCount > 0) {
            log.info("为用户{}加载房间{}的历史消息，共{}条", userId, roomId, messageCount);

            List<String> historyMessages = redisCacheUtil.getListOperations().range(cacheKey, 0, -1);
            if (historyMessages != null && !historyMessages.isEmpty()) {
                log.info("实际获取到的历史消息数量：{}", historyMessages.size());
                List<JSONObject> parsedMessages = new ArrayList<>();
                for (String messageStr : historyMessages) {
                    try {
                        JSONObject messageObj = JSON.parseObject(messageStr);
                        parsedMessages.add(messageObj);
                    } catch (Exception e) {
                        log.error("解析历史消息失败，消息内容：{}", messageStr, e);
                    }
                }
                JSONObject historyMsg = new JSONObject();
                historyMsg.put("type", "history");
                historyMsg.put("messages", parsedMessages);
                historyMsg.put("count", parsedMessages.size());
                sendMessage(historyMsg.toJSONString());
                log.info("已向用户{}发送{}条历史消息", userId, parsedMessages.size());
            }
        } else {
            log.info("房间{}没有历史消息，缓存键：{}", roomId, cacheKey);
        }
    }

    public static  synchronized  int getOnlineCount(){
        return onlineCount;
    }

    public static  synchronized  void addOnlineCount(){
        WebSocketService.onlineCount++;
    }

    public static  synchronized void subOnlineCount(){
        WebSocketService.onlineCount--;
    }
    public static ConcurrentHashMap<String, Room> getRoomMap() {
        return roomMap;
    }

}
